package com.xiaobo.sql.component.query;

import com.xiaobo.sql.base.Column;
import com.xiaobo.sql.base.Join;
import com.xiaobo.sql.base.Table;
import com.xiaobo.sql.component.condition.AbstractCondition;
import com.xiaobo.sql.utils.SqlUtils;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * 查询类
 * @author duxiaobo
 * @date 2021/11/244:45 下午
 */
public class Select implements Table {
    private List<Column> columns;
    private List<Table> froms;
    private List<Join> joins;
    private AbstractCondition condition;
    private List<Column> groupBy;
    private String aliasName;

    public Select() {
    }

    public List<Column> getColumns() {
        return columns;
    }

    public Select setColumns(List<Column> columns) {
        this.columns = columns;
        return this;
    }

    public Select addColumn(Column column) {
        if (Objects.isNull(this.columns)) {
            this.columns = new LinkedList<>();
        }
        Collections.addAll(this.columns, column);
        return this;
    }

    public List<Table> getFroms() {
        return froms;
    }

    public Select setFroms(List<Table> froms) {
        this.froms = froms;
        return this;
    }

    public Select addFrom(Table table) {
        if (Objects.isNull(this.froms)) {
            this.froms = new LinkedList<>();
        }
        Collections.addAll(this.froms, table);
        return this;
    }

    public List<Join> getJoins() {
        return joins;
    }

    public Select setJoins(List<Join> joins) {
        this.joins = joins;
        return this;
    }

    public Select addJoins(Join join) {
        if (Objects.isNull(this.joins)) {
            this.joins = new LinkedList<>();
        }
        Collections.addAll(this.joins, join);
        return this;
    }

    public AbstractCondition getCondition() {
        return condition;
    }

    public Select setCondition(AbstractCondition condition) {
        this.condition = condition;
        return this;
    }

    public Select as(String aliasName) {
        this.aliasName = aliasName;
        return this;
    }

    @Override
    public String toSqlAsValue() {
        StringBuilder sql = new StringBuilder();
        sql.append("(");
        toSql(sql);
        sql.append(")");
        return sql.toString();
    }

    @Override
    public void toSql(StringBuilder sql) {
        sql.append("SELECT ");
        column(sql);
        sql.append(" FROM ");
        from(sql);
        join(sql);
        if (Objects.nonNull(this.condition)) {
            sql.append(" WHERE ");
            this.condition.toSql(sql);
        }
        group(sql);


    }

    private void group(StringBuilder sql) {
        if (Objects.isNull(this.groupBy)) {
            return;
        }
        sql.append(" GROUP BY ");
        for (int i = 0; i < groupBy.size(); i++) {
            if (i == groupBy.size() - 1) {
                sql.append(groupBy.get(i).toSqlAsValue());
            } else {
                sql.append(groupBy.get(i).toSqlAsValue());
                sql.append(",");
            }
        }
    }


    private void join(StringBuilder sql) {
        if (Objects.isNull(this.joins)) {
            return;
        }
        for (int i = 0; i < this.joins.size(); i++) {
            if (i == this.joins.size() - 1) {
                this.joins.get(i).toSql(sql);
            } else {
                this.joins.get(i).toSql(sql);
                sql.append(",");
            }
        }
    }

    private void from(StringBuilder sql) {
        if (Objects.isNull(this.froms)) {
            return;
        }
        for (int i = 0; i < froms.size(); i++) {
            if (i == froms.size() - 1) {
                froms.get(i).toSql(sql);
            } else {
                froms.get(i).toSql(sql);
                sql.append(",");
            }
        }

    }

    private void column(StringBuilder sql) {
        if (Objects.isNull(this.columns)) {
            return;
        }
        for (int i = 0; i < columns.size(); i++) {
            if (i == columns.size() - 1) {
                columns.get(i).toSql(sql);
            } else {
                columns.get(i).toSql(sql);
                sql.append(",");
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder sql = new StringBuilder();
        toSql(sql);
        sql.append(";");
        return sql.toString();
    }

    @Override
    public String toSqlToValueWithAS() {
        StringBuilder sql = new StringBuilder();
        sql.append(toSqlAsValue());
        if (Objects.nonNull(this.aliasName)) {
            sql.append(" AS ");
            SqlUtils.appendSymbol(this.aliasName, sql);
        }
        return sql.toString();
    }
}
